﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

namespace GpuProgramCompiler.Compilers
{
    class ShaderCompilerDX9
    {
        public ShaderCompilerDX9(CmdLineArgs args, ref CompiledShader outCompiledShader)
        {
			Byte[] pixelShaderCode;
			Byte[] vertexShaderCode;
			String[] pixelShaderConstants;
			String[] vertexShaderConstants;

			Helpers.CompileShader(args["IN"], "ps_3_0", "ps_main", "dx9", args["DEBUGINFO"] != null, out pixelShaderCode, out pixelShaderConstants);
			Helpers.CompileShader(args["IN"], "vs_3_0", "vs_main", "dx9", args["DEBUGINFO"] != null, out vertexShaderCode, out vertexShaderConstants);

			if (vertexShaderCode != null)
			{
				OutputShader(vertexShaderCode, "VertexShader", outCompiledShader);
				OutputConstantTable(vertexShaderConstants, "VertexShader", outCompiledShader);
			}

			if (pixelShaderCode != null)
			{
				OutputShader(pixelShaderCode, "PixelShader", outCompiledShader);
				OutputConstantTable(pixelShaderConstants, "PixelShader", outCompiledShader);
			}
        }

		void OutputShader(Byte[] shaderCode, String name, CompiledShader compiledShader)
		{
			compiledShader.Programs.Add(new CompiledShader.Program(name, name, shaderCode));
		}

		void OutputConstantTable(String[] constants, String name, CompiledShader compiledShader)
		{
			if (constants != null)
			{
				CompiledShader.ConstantTable floatTable = new CompiledShader.ConstantTable();
				floatTable.Name = name + "Floats";

				CompiledShader.ConstantTable intTable = new CompiledShader.ConstantTable();
				intTable.Name = name + "Ints";
				
				CompiledShader.ConstantTable boolTable = new CompiledShader.ConstantTable();
				boolTable.Name = name + "Bools";

				CompiledShader.ConstantTable textureTable = new CompiledShader.ConstantTable();
				textureTable.Name = name + "Textures";

				foreach (String constant in constants)
				{
					CompiledShader.Constant newConstant = ExtractShaderConstant(constant);

					if (newConstant.Type.Contains("TEXTURE"))
					{
						textureTable.Constants.Add(newConstant);
					}
					else if (newConstant.Type.Contains("FLOAT"))
					{
						floatTable.Constants.Add(newConstant);
					}
					else if (newConstant.Type.Contains("INT"))
					{
						intTable.Constants.Add(newConstant);
					}
					else if (newConstant.Type.Contains("BOOL"))
					{
						boolTable.Constants.Add(newConstant);
					}
				}

				if (floatTable.Constants.Count > 0)
					compiledShader.ConstantTables.Add(floatTable);

				if (intTable.Constants.Count > 0)
					compiledShader.ConstantTables.Add(intTable);

				if (boolTable.Constants.Count > 0)
					compiledShader.ConstantTables.Add(boolTable);

				if (textureTable.Constants.Count > 0)
					compiledShader.ConstantTables.Add(textureTable);
			}
		}

		CompiledShader.Constant ExtractShaderConstant(String line)
		{
			String[] lineBits = line.Split('*');

			String name = lineBits[0];
			String registerSet = lineBits[1];
			int registerIndex = int.Parse(lineBits[2]);
			int registerCount = int.Parse(lineBits[3]);
			String constantClass = lineBits[4];
			String constantType = lineBits[5];
			int rows = int.Parse(lineBits[6]);
			int columns = int.Parse(lineBits[7]);
			int elements = int.Parse(lineBits[8]);
			int structMembers = int.Parse(lineBits[9]);

			if (name.Contains("+"))
			{
				name = name.Split('+')[1];
			}

			UInt32 constantNameCRC = Crc.GetInstance().GenerateCrc(name);
			UInt32 registerSetCRC = Crc.GetInstance().GenerateCrc(registerSet);
			UInt32 constantClassCRC = Crc.GetInstance().GenerateCrc(constantClass);
			UInt32 constantTypeCRC = Crc.GetInstance().GenerateCrc(constantType);

// 			writer.Write(constantNameCRC);
// 			writer.Write(constantNameCRC);	// semantic
// 			writer.Write(registerSetCRC);
// 			writer.Write(registerIndex);
// 			writer.Write(registerCount);
// 			writer.Write(constantClassCRC);
// 			writer.Write(constantTypeCRC);
// 			writer.Write(rows);
// 			writer.Write(columns);
// 			writer.Write(elements);
// 			writer.Write(structMembers);

			CompiledShader.Constant newConstant = new CompiledShader.Constant();
			newConstant.Name = name;
			newConstant.Type = constantType;
			newConstant.Offset = registerIndex;
			newConstant.Size = registerCount;

			return newConstant;
		}
    }
}